package soar.test.reflection;

import java.util.Arrays;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class App
{
    public static void main(String args[])
    {
        new App().run();
    }

    private void run()
    {
        try
        {
            String split = "========================================";
            System.out.println(split);

            reflection();
            System.out.println(split);
            
            performance();
            System.out.println(split);
        }
        catch (Exception e)
        {
            System.out.println(e);
            return;
        }
    }

    private void reflection() throws Exception
    {
        String split = "------------------------------";
        System.out.println("reflection");
        System.out.println(split);
        
        Class<?> cls = Class.forName("soar.test.reflection.Reflect");
        Class<?> cls_super=cls.getSuperclass();
        Object obj = (Object) cls.newInstance();

        System.out.println("getFields");
        Field[] fields = cls.getFields();
        for (Field f : fields)
        {
            System.out.println(f.getName());
            if (f.getType() == String.class)
            {
                System.out.println("String: " + f.get(obj));
            }
            else
            {
                System.out.println("int: " + f.getInt(obj));
            }
        }
        System.out.println();
        
        System.out.println("getDeclaredFields");
        fields = cls.getDeclaredFields();
        for (Field f : fields)
        {
            f.setAccessible(true);
            System.out.println(f.getName());
            if (f.getType() == String.class)
            {
                System.out.println("String: " + f.get(obj));
            }
            else
            {
                System.out.println("int: " + f.getInt(obj));
            }
        }
        System.out.println();
        
        System.out.println("父类getDeclaredFields");
        fields = cls_super.getDeclaredFields();
        for (Field f : fields)
        {
            f.setAccessible(true);
            System.out.println(f.getName());
            if (f.getType() == String.class)
            {
                System.out.println("String: " + f.get(obj));
            }
            else
            {
                System.out.println("int: " + f.getInt(obj));
            }
        }
        System.out.println();

        System.out.println("getDeclaredMethods");
        Method[] methods = cls.getDeclaredMethods();
        for (Method m : methods)
        {
            System.out.println(m.toString());
        }
        System.out.println();

        System.out.println(split);
        
        System.out.println("调用 new Reflect().hello(\"OK\")");
        new Reflect().hello("OK");
        
        System.out.println();
        
        System.out.println("反射调用");
        Class<?>[] args_type = new Class[1];
        args_type[0] = Class.forName("java.lang.String");
        Method m = cls.getMethod("hello", args_type);
        Object[] args = new Object[1];
        args[0] = new String("World");
        Object res = m.invoke(obj, args);
        System.out.println((Boolean) res);
    }

    private void performance() throws Exception
    {
        String split = "------------------------------";
        System.out.println("performance");
        System.out.println(split);
        
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss:SSS");
        Date begin = new Date();
        for (int i = 0; i < 1000000; ++i)
        {
            Class<?> cls = Class.forName("java.lang.String");
            Class<?>[] cls_types = new Class[] { String.class };
            Constructor<?> ctor = cls.getConstructor(cls_types);
            Object[] cls_args = new Object[] { "aa hello bb world" };
            Object ins = ctor.newInstance(cls_args);

            Class<?>[] args_type = new Class[] { String.class, int.class };
            Object[] args = new Object[2];
            args[0] = "hello";
            args[1] = 10;
            Method method = cls.getMethod("lastIndexOf", args_type);
            Object res = method.invoke(ins, args);
            // System.out.println((Integer)res);
        }
        Date end = new Date();
        System.out.println(String.format("Class.forName: %s - %s %d ms",
                format.format(begin), format.format(end),
                (end.getTime() - begin.getTime())));

        begin = new Date();
        for (int i = 0; i < 1000000; ++i)
        {
            String ins = "aa hello bb world";
            int res = ins.lastIndexOf("hello", 10);
        }
        end = new Date();
        System.out.println(
                String.format("Static: %s - %s %d ms", format.format(begin),
                        format.format(end), (end.getTime() - begin.getTime())));
    }
}

class ReflectBase
{
    protected int base_i = 100;

    public int getBase_i()
    {
        return base_i;
    }

    public void setBase_i(int base_i)
    {
        this.base_i = base_i;
    }

}

class Reflect extends ReflectBase
{
    private int i1 = 200;

    public int i2 = 1999;
    public String s2 = "hi";

    public int getI1()
    {
        return i1;
    }

    public void setI1(int i1)
    {
        this.i1 = i1;
    }

    private String func1(String s)
    {
        return s + " " + new Date().toString();
    }

    public boolean hello(String s)
    {
        System.out.println(func1("Hello " + s));
        return true;
    }
}
